package me.zhengjie.minbearwcs.serivce.mission.generate.rework;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.minbearwcs.dao.mission.inf.WcsMissionDao;
import me.zhengjie.minbearwcs.dao.outbound.inf.OutboundDao;
import me.zhengjie.minbearwcs.dao.rework.inf.ReworkOrderDetailDao;
import me.zhengjie.minbearwcs.dao.rework.inf.ReworkTaskRecordDao;
import me.zhengjie.minbearwcs.dao.storage.inf.LargeStorageDao;
import me.zhengjie.minbearwcs.dao.storage.inf.SmallStorageDao;
import me.zhengjie.minbearwcs.dao.storage.inf.StorageDao;
import me.zhengjie.minbearwcs.entity.DTO.transfer.Tuple;
import me.zhengjie.minbearwcs.entity.PO.wcs.mission.WcsMission;
import me.zhengjie.minbearwcs.entity.PO.wcs.mission.status.ReworkMissionStatus;
import me.zhengjie.minbearwcs.entity.PO.wcs.mission.status.ReworkShiftingMissionStatus;
import me.zhengjie.minbearwcs.entity.PO.wcs.mission.type.MissionType;
import me.zhengjie.minbearwcs.entity.PO.wcs.outbound.stockUp.PalletMediumStorageSearchPo;
import me.zhengjie.minbearwcs.entity.PO.wcs.rework.ReworkOrderDetail;
import me.zhengjie.minbearwcs.entity.PO.wcs.rework.ReworkTaskRecord;
import me.zhengjie.minbearwcs.entity.PO.wcs.rework.status.ReworkTaskRecordStatus;
import me.zhengjie.minbearwcs.entity.PO.wcs.storage.SmallStorage;
import me.zhengjie.minbearwcs.serivce.mission.generate.MissionGenerator;
import me.zhengjie.minbearwcs.serivce.mission.generate.type.MissionGenType;
import me.zhengjie.minbearwcs.serivce.mission.storageProcessor.locker.Floor5Or6.ShiftingStorage5Or6FloorLocker;
import me.zhengjie.minbearwcs.utils.ContentPool;
import me.zhengjie.minbearwcs.utils.IdWorker;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Component
@RequiredArgsConstructor
public class ReworkGenerator implements MissionGenerator<String> {

    private final SmallStorageDao smallStorageDao;
    private final OutboundDao outboundDao;
    private final WcsMissionDao wcsMissionDao;
    private final IdWorker idWorker;
    private final ReworkOrderDetailDao reworkOrderDetailDao;
    private final StorageDao storageDao;
    private final LargeStorageDao largeStorageDao;
    private final ShiftingStorage5Or6FloorLocker shiftingStorage5Or6FloorLocker;
    private final ReworkTaskRecordDao reworkTaskRecordDao;

    @Override
    public MissionGenType type() {
        return MissionGenType.REWORK;
    }

    @Override
    public Tuple<String> generate(Object source) {
        List<ReworkOrderDetail> reworkOrderDetailList = (List<ReworkOrderDetail>) source;
        String reworkOrderCode = reworkOrderDetailList.get(0).getReworkOrderCode();

        HashSet<String> canNotShiftingStorage = new HashSet<>();


        for (ReworkOrderDetail reworkOrderDetail : reworkOrderDetailList) {
            String palletCode = reworkOrderDetail.getPalletCode();
            SmallStorage smallStorage = smallStorageDao.selectByPallet(palletCode);
            if (smallStorage == null) {
                return Tuple.tuple("栈板： " + palletCode + " 不在库区，返工失败", false);
            }

            if (smallStorage.getOutboundFreezePallet() != null) {
                return Tuple.tuple("栈板： " + palletCode + " 执行任务中，返工失败", false);
            }

            List<SmallStorage> storageList = smallStorageDao.selectSmallStorageByMediunStorage(smallStorage.getMediumStorageCode());

            long count = storageList.stream()
                    .filter(a -> a.getInboundFreezePallet() != null)
                    .count();

            if (count > 0) {
                return Tuple.tuple("栈板： " + palletCode + " 所处中储位有入库任务，返工失败", false);
            }

            storageList.forEach(a -> canNotShiftingStorage.add(a.getSmallStorageCode()));
        }


        Set<String> needReworkSet = reworkOrderDetailList.stream()
                .map(ReworkOrderDetail::getPalletCode)
                .collect(Collectors.toSet());


        HashSet<String> handlePalletSet = new HashSet<>();

        for (ReworkOrderDetail reworkOrderDetail : reworkOrderDetailList) {
            if (handlePalletSet.contains(reworkOrderDetail.getPalletCode())) continue;


            SmallStorage smallStorage = smallStorageDao.selectByPallet(reworkOrderDetail.getPalletCode());
            List<PalletMediumStorageSearchPo> palletMediumStorageSearchPoList = outboundDao.selectPalletMediumStorage(smallStorage.getMediumStorageCode());


            // 计算这个中储位要处理多少个
            long mediumNeedHandleNum = palletMediumStorageSearchPoList.stream()
                    .filter(a -> {
                        if (needReworkSet.contains(a.getPalletCode())) {
                            handlePalletSet.add(a.getPalletCode());
                            return true;
                        } else {
                            return false;
                        }
                    })
                    .count();


            long enterCount = palletMediumStorageSearchPoList.stream()
                    .filter(a -> a.getIsEntrance() == ContentPool.STORAGE_IS_ENTER)
                    .count();


            if (enterCount == 2) {
                reworkBackToFront(needReworkSet,palletMediumStorageSearchPoList,mediumNeedHandleNum,reworkOrderCode,
                        reworkOrderDetailList,smallStorage.getMediumStorageCode());
            } else if (enterCount == 1) {
                PalletMediumStorageSearchPo palletMediumStorageSearchPo = palletMediumStorageSearchPoList.get(0);
                if (palletMediumStorageSearchPo.getIsEntrance().equals(ContentPool.STORAGE_IS_ENTER)){
                    reworkFrontToBack(needReworkSet,palletMediumStorageSearchPoList,mediumNeedHandleNum,reworkOrderCode,
                            reworkOrderDetailList,smallStorage.getMediumStorageCode());
                }else {
                    reworkBackToFront(needReworkSet,palletMediumStorageSearchPoList,mediumNeedHandleNum,reworkOrderCode,
                            reworkOrderDetailList,smallStorage.getMediumStorageCode());
                }

            } else {
                return Tuple.tuple("该储位没有出口，请检查", false);
            }

        }

        return Tuple.tuple(null,true);
    }


    private void reworkFrontToBack(Set<String> needReworkSet, List<PalletMediumStorageSearchPo> palletMediumStorageSearchPoList, long mediumNeedHandleNum, String reworkOrderCode, List<ReworkOrderDetail> reworkOrderDetailList,String mediumStorage) {
        String waitSmallStorage = null;
        String lastReworkOrderDetailCode = null;

        for (int i = 0; i < palletMediumStorageSearchPoList.size(); i++) {
            if (mediumNeedHandleNum == 0) break;

            PalletMediumStorageSearchPo tempStorage = palletMediumStorageSearchPoList.get(i);

            if (needReworkSet.contains(tempStorage.getPalletCode())) {
                Optional<ReworkOrderDetail> optional = reworkOrderDetailList.stream()
                        .filter(a -> a.getPalletCode().equals(tempStorage.getPalletCode()))
                        .findAny();
                ReworkOrderDetail reworkOrderDetail = optional.get();
                lastReworkOrderDetailCode = reworkOrderDetail.getReworkOrderDetailCode();

                createReworkMission(tempStorage.getPalletCode(), tempStorage.getSmallStorageCode(), reworkOrderDetail.getReworkOrderCode(),
                        reworkOrderDetail.getReworkOrderDetailCode(), waitSmallStorage);
                mediumNeedHandleNum--;

            }else if (tempStorage.getPalletCode() != null && tempStorage.getOutboundFreezePallet() == null){
                Tuple<String> lockStorage = shiftingStorage5Or6FloorLocker.lockInStorage(
                        tempStorage.getMaterialCode(),
                        tempStorage.getInboundOrderCode(),
                        tempStorage.getBatchCode(),
                        tempStorage.getPalletCode(),
                        mediumStorage
                );

                if (!lockStorage.success) {
                    throw new RuntimeException(tempStorage.getPalletCode() + " 没找到能移库的储位");
                }

                createReworkShiftingMission(tempStorage.getPalletCode(), tempStorage.getSmallStorageCode(), lockStorage.value
                        ,reworkOrderCode, lastReworkOrderDetailCode, waitSmallStorage);
                mediumNeedHandleNum--;
            }



            // 标记上一个等待的小储位
            if (tempStorage.getPalletCode() != null) {
                waitSmallStorage = tempStorage.getSmallStorageCode();
            }
        }

    }

    private void reworkBackToFront(Set<String> needReworkSet, List<PalletMediumStorageSearchPo> palletMediumStorageSearchPoList, long mediumNeedHandleNum, String reworkOrderCode, List<ReworkOrderDetail> reworkOrderDetailList,String mediumStorage) {
        String waitSmallStorage = null;
        String lastReworkOrderDetailCode = null;

        for (int j = palletMediumStorageSearchPoList.size() - 1; j >= 0; j--) {
            if (mediumNeedHandleNum == 0) break;

            PalletMediumStorageSearchPo tempStorage = palletMediumStorageSearchPoList.get(j);

            if (needReworkSet.contains(tempStorage.getPalletCode())) {
                Optional<ReworkOrderDetail> optional = reworkOrderDetailList.stream()
                        .filter(a -> a.getPalletCode().equals(tempStorage.getPalletCode()))
                        .findAny();
                ReworkOrderDetail reworkOrderDetail = optional.get();
                lastReworkOrderDetailCode = reworkOrderDetail.getReworkOrderDetailCode();

                createReworkMission(tempStorage.getPalletCode(), tempStorage.getSmallStorageCode(), reworkOrderDetail.getReworkOrderCode(),
                        reworkOrderDetail.getReworkOrderDetailCode(), waitSmallStorage);
                mediumNeedHandleNum--;

            }else if (tempStorage.getPalletCode() != null && tempStorage.getOutboundFreezePallet() == null){
                Tuple<String> lockStorage = shiftingStorage5Or6FloorLocker.lockInStorage(
                        tempStorage.getMaterialCode(),
                        tempStorage.getInboundOrderCode(),
                        tempStorage.getBatchCode(),
                        tempStorage.getPalletCode(),
                        mediumStorage
                );

                if (!lockStorage.success) {
                    throw new RuntimeException(tempStorage.getPalletCode() + " 没找到能移库的储位");
                }

                createReworkShiftingMission(tempStorage.getPalletCode(), tempStorage.getSmallStorageCode(), lockStorage.value
                        ,reworkOrderCode, lastReworkOrderDetailCode, waitSmallStorage);
            }



            // 标记上一个等待的小储位
            if (tempStorage.getPalletCode() != null) {
                waitSmallStorage = tempStorage.getSmallStorageCode();
            }
        }
    }


    private void createReworkMission(String palletCode, String startPoint, String reworkOrderCode, String reworkDetailCode, String waitSmallSotrage) {
        shiftingStorage5Or6FloorLocker.lockOutStorage(startPoint, palletCode);

        String recordId = "Rework_Record_" + idWorker.nextId();
        ReworkTaskRecord reworkTaskRecord = new ReworkTaskRecord(null, recordId, reworkOrderCode, reworkDetailCode, palletCode, ReworkTaskRecordStatus.INIT,
                startPoint, null, MissionType.REWORK, waitSmallSotrage, null, null);

        reworkTaskRecordDao.insert(reworkTaskRecord);

        String missionId = "Task_Rework_" + idWorker.nextId();
        WcsMission mission = new WcsMission(null, missionId, recordId, MissionType.REWORK.name(),
                ReworkMissionStatus.WAIT_FOR_STORAGE.name(), LocalDateTime.now(), null, null,
                1, recordId);
        wcsMissionDao.insert(mission);
        log.info("栈板 {} ，返工单 {}，返工明细 {} ，返工Record记录 {} ，返工wcs任务 {} 生成成功",
                palletCode, reworkOrderCode, reworkDetailCode, recordId, missionId);
    }


    private void createReworkShiftingMission(String palletCode, String startPoint, String endPoint, String reworkOrderCode, String reworkDetailCode, String waitSmallSotrage) {
        shiftingStorage5Or6FloorLocker.lockOutStorage(startPoint, palletCode);

        String recordId = "Rework_Shifting_Record_" + idWorker.nextId();
        ReworkTaskRecord reworkTaskRecord = new ReworkTaskRecord(null, recordId, reworkOrderCode, null, palletCode, ReworkTaskRecordStatus.INIT,
                startPoint, endPoint, MissionType.REWORK_SHIFTING, waitSmallSotrage, null, null);

        reworkTaskRecordDao.insert(reworkTaskRecord);

        String missionId = "Task_Rework_Shifting_" + idWorker.nextId();
        WcsMission mission = new WcsMission(null, missionId, recordId, MissionType.REWORK_SHIFTING.name(),
                ReworkShiftingMissionStatus.WAIT_FOR_DISPATCH.name(), LocalDateTime.now(), null, null,
                1, recordId);
        wcsMissionDao.insert(mission);
        log.info("栈板 {} ，返工单 {}，返工明细 {} ，返工Record记录 {} ，返工移库wcs任务 {} 生成成功",
                palletCode, reworkOrderCode, reworkDetailCode, recordId, missionId);
    }

}
